package com.lagou.edu.factory;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static java.lang.Class.forName;

/**
 * @author oyz
 * 工厂类，生产对象(使用反射技术)
 */
public class BeanFactory {

    /**
     * 任务一: 读取解析xml,通过反射技术实例化对象并且存储待用
     * 任务二: 对外提供获取实例对象的接口(根据id获取)
     */

    //存储对象
    private static Map<String,Object> map = new HashMap<>(16);


    static {
        // 任务一: 读取解析xml,通过反射技术实例化对象并且存储待用
        InputStream resourceAsStream = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");
        // 解析xml
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(resourceAsStream);
            Element rootElement = document.getRootElement();
            List<Element> list = rootElement.selectNodes("//bean");
            for (Element element : list) {
                String id = element.attributeValue("id");
                String clazz = element.attributeValue("class");
                // 通过反射获取到实例化对象
                Class<?> aClass = forName(clazz);
                // 实例化获得的对象
                Object o = aClass.newInstance();
                // 存储到map中待用
                map.put(id,o);
            }
            // 实例化完成对象之后维护对象的依赖关系，检查对象那些值需要传值进入的，根据它的配置，我们传入相应的值
            // 有property子元素的bean就有传值的需求
             List<Element> propertyList = rootElement.selectNodes("//property");
            // 解析property获取父元素
            for (int i = 0; i < propertyList.size(); i++) {
                // <property name="AccountDao" ref="accountDao"></property>
                Element element = propertyList.get(i);
                String  name = element.attributeValue("name");
                String ref = element.attributeValue("ref");
                // 找到当前被处理关系的bean
                Element parent = element.getParent();
                String parentId = parent.attributeValue("id");
                // 通过map容器拿到父对象
                Object parentObject = map.get(parentId);
                // 遍历父对象的所有方法,拿到"set"+name方法
                Method[] methods = parentObject.getClass().getMethods();
                for (int j = 0; j < methods.length; j++) {
                    Method method = methods[j];
                    if(method.getName().equalsIgnoreCase("set"+name)){
                        method.invoke(parentObject,map.get(ref));

                    }
                    
                }
                // 把处理好的parentObject重新放入map
                map.put(parentId,parentObject);

            }


        } catch (DocumentException | ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    // 任务二: 对外提供获取实例对象的接口(根据id获取)
    public static Object getBean(String id){
        return map.get(id);
    }


    public static void main(String[] args) {
        new BeanFactory();
        //InputStream resourceAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("beans.xml");
        //System.out.println(resourceAsStream);
    }



}
